home *** CD-ROM | disk | FTP | other *** search
/ Chip 2007 January, February, March & April / Chip-Cover-CD-2007-02.iso / Pakiet bezpieczenstwa / mini Pentoo LiveCD 2006.1 / mpentoo-2006.1.iso / modules / nessus-2.2.8.mo / usr / lib / nessus / plugins / webmirror.nasl < prev    next >
Text File  |  2005-01-14  |  27KB  |  1,238 lines

  1. #
  2. # WEBMIRROR 2.0
  3. #
  4. #
  5. # Written by Renaud Deraison <deraison@nessus.org>
  6. # includes some code by H D Moore <hdmoore@digitaldefense.net>
  7. #
  8. # This plugin mirrors the paths used by a website. We typically care
  9. # to obtain the list of CGIs installed on the remote host, as well as
  10. # the path they are installed under. 
  11. #
  12. # Note that this plugin does not properly check for the syntax of the
  13. # HTML pages returned : it tries to extract as much info as it
  14. # can. We don't care about the pages extensions either (but we do
  15. # case about the mime types)
  16. #
  17. # This plugin takes a really long time to complete, so it updates
  18. # the KB as soon as data is found (as it's likely to be killed
  19. # by nessusd against huge sites)
  20. #
  21. # Features :
  22. #
  23. #  o Directories are added in additions to URIs (ie: if there is a link to /foo/bar/a.gif, then webmirror
  24. #    will crawl /foo/bar/)
  25. #  o Apache and iPlanet directory listing features are used (/foo/bar will be requested as /foo/bar?D=A and
  26. #    /foo/bar/?PageServices)   [thanks to MaXX and/or Nicolas Fischbach for the suggestion]
  27. #  o Content is stored by various keys in the kb, to be easily reused by other scripts
  28. #  o Forms and URIs ending in '?.*' are recognized and a list of CGIs is made from them
  29. #  o Keep-alive support
  30. #
  31. # See also :
  32. #  o torturecgis.nasl
  33. #  o bakfiles.nasl
  34. #  o officefiles.nasl
  35. #
  36. # This is version 2.0 of the plugin - it should be WAY faster and more
  37. # accurate (i wrote a real parser).
  38. #
  39. #
  40. # See the Nessus Scripts License for details
  41. #
  42.  
  43. if(description)
  44. {
  45.  script_id(10662);
  46.  # script_cve_id("CVE-MAP-NOMATCH");
  47.  script_version("$Revision: 1.87 $");
  48.  
  49.  name["english"] = "Web mirroring";
  50.  name["francais"] = "Web mirroring";
  51.  script_name(english:name["english"], francais:name["francais"]);
  52.  
  53.  desc["english"] = "
  54. This script makes a mirror of the remote web site(s)
  55. and extracts the list of CGIs that are used by the remote
  56. host.
  57.  
  58. It is suggested you give a high timeout value to
  59. this plugin and that you change the number of
  60. pages to mirror in the 'Options' section of
  61. the client.
  62.  
  63. Risk factor : None";
  64.  
  65.  script_description(english:desc["english"]);
  66.  
  67.  summary["english"] = "Performs a quick web mirror";
  68.  summary["francais"] = "Effectue un miroir rapide de site web";
  69.  
  70.  script_summary(english:summary["english"], francais:summary["francais"]);
  71.  
  72.  script_category(ACT_GATHER_INFO);
  73.  
  74.  
  75.  script_copyright(english:"This script is Copyright (C) 2001 - 2003 Renaud Deraison",
  76.         francais:"Ce script est Copyright (C) 2001 - 2003 Renaud Deraison");
  77.  family["english"] = "CGI abuses";
  78.  family["francais"] = "Abus de CGI";
  79.  script_family(english:family["english"], francais:family["francais"]);
  80.  script_dependencie("find_service.nes", "httpver.nasl", "DDI_Directory_Scanner.nasl");
  81.  script_require_ports("Services/www", 80);
  82.  # There was a memory leak that made webmirror eat much memory
  83.  # It is now fixed but there was no NASL_LEVEL defined for it. However,
  84.  # we know that NASL_LEVEL was increased to 2181 _after_ the fix
  85.  # Better than nothing...
  86.  if (NASL_LEVEL >= 2181)
  87.  script_add_preference(name:"Number of pages to mirror : ",
  88.              type:"entry",
  89.             value:"200");
  90.  else
  91.  script_add_preference(name:"Number of pages to mirror : ",
  92.              type:"entry",
  93.             value:"20");
  94.  script_add_preference(name:"Start page : ",
  95.              type:"entry",
  96.             value:"/");            
  97.  exit(0);
  98. }
  99.  
  100. include("http_func.inc");
  101. include("http_keepalive.inc");
  102. include("global_settings.inc");
  103.  
  104.  
  105. #-------------------------------------------------------------------------#
  106.  
  107. function my_http_recv(socket)
  108. {
  109.   local_var    h, b, l;
  110.  
  111.   h = http_recv_headers(socket);
  112.   if(!h)return(NULL);
  113.   
  114.   if("Content-Type" >< h)
  115.   {
  116.    if(!egrep(pattern:"^Content-Type: text/(xml|html)", string:h))return(h);
  117.   }
  118.   
  119.   b = http_recv_body(socket: socket, headers: h, length:0);
  120.   return (string(h, "\r\n", b));
  121. }
  122.  
  123.  
  124.  
  125. function my_http_keepalive_recv()
  126. {
  127.   local_var headers, body, length, tmp, chunked, killme;
  128.  
  129.   killme = 0;
  130.   length = -1;
  131.   headers = http_recv_headers(__ka_socket);
  132.   if(strlen(headers) == 0)headers = http_recv_headers(__ka_socket);
  133.   
  134.   if(ereg(pattern:"^HEAD.*HTTP/.*", string:__ka_last_request))
  135.    {
  136.    # HEAD does not return a body
  137.    return(headers);
  138.    }
  139.   
  140.   if("Content-Type" >< headers)
  141.   {
  142.    if(!egrep(pattern:"^Content-Type: text/(xml|html)", string:headers))
  143.        {
  144.      http_close_socket(__ka_socket);
  145.      __ka_socket = 0;
  146.      return(headers);
  147.     }
  148.   }
  149.   
  150.   if("Content-Length" >< headers)
  151.   {
  152.     tmp = egrep(string:headers, pattern:"^Content-Length: [0-9]*");
  153.     length = int(ereg_replace(string:tmp, pattern:"^Content-Length: ([0-9]*)", replace:"\1"));
  154.   }
  155.   
  156.  
  157.  
  158.  if((length < 0) && (egrep(pattern:"transfer-encoding: chunked", string:headers, icase:TRUE)))
  159.  {
  160.    while(1)
  161.    {
  162.    tmp = recv_line(socket:__ka_socket, length:4096);
  163.    length = hex2dec(xvalue:tmp);
  164.    if(length > 512*1024)
  165.        {
  166.        length = 512*1024;
  167.     killme = 1;
  168.     }
  169.    body  = string(body, recv(socket:__ka_socket, length:length+2, min:length+2));
  170.    if(strlen(body) > 512*1024)killme = 1;
  171.    
  172.    if(length == 0 || killme){
  173.        http_keepalive_check_connection(headers:headers);
  174.        return(string(headers,"\r\n", body)); # This is expected - don't put this line before the previous
  175.     }
  176.    }
  177.  }
  178.  
  179.  
  180.  if(length >= 0)
  181.  {
  182.    if(length > 512*1024)length = 512*1024;
  183.    
  184.    body = recv(socket:__ka_socket, length:length, min:length);
  185.  }
  186.  else {
  187.      # If we don't have the length, we close the connection to make sure
  188.     # the next request won't mix up the replies.
  189.     
  190.      #display("ERROR - Keep Alive, but no length!!!\n", __ka_last_request);
  191.     body = recv(socket:__ka_socket, length:16384);
  192.     http_close_socket(__ka_socket);
  193.     __ka_socket =  http_open_socket(__ka_port);
  194.     }
  195.  
  196.  
  197.  
  198.  http_keepalive_check_connection(headers:headers);
  199.  return(string(headers,"\r\n", body));
  200. }
  201.  
  202.  
  203.  
  204. function my_http_keepalive_send_recv(port, data)
  205. {
  206.   local_var id, n;
  207.   
  208.   if(data == NULL)
  209.    return;
  210.  
  211.   if(__ka_enabled == -1)__ka_enabled = http_keepalive_enabled(port:port);
  212.  
  213.  
  214.  
  215.   if(__ka_enabled == 0)
  216.   {
  217.     local_var soc, r;
  218.     soc = http_open_socket(port);
  219.     if(!soc)return NULL;
  220.     send(socket:soc, data:data);
  221.     r = my_http_recv(socket:soc);
  222.     http_close_socket(soc);
  223.     return r;
  224.   }
  225.  
  226.  
  227.   if((port != __ka_port)||(!__ka_socket))
  228.   {
  229.     if(__ka_socket)http_close_socket(__ka_socket);
  230.     __ka_port = port;
  231.     __ka_socket =  http_open_socket(port);
  232.     if(!__ka_socket)return NULL;
  233.   }
  234.  
  235.   id = stridx(data, string("\r\n\r\n"));
  236.   data = str_replace(string:data, find:"Connection: Close", replace:"Connection: Keep-Alive", count:1);
  237.   __ka_last_request = data;
  238.   n = send(socket:__ka_socket, data:data);
  239.   if(n <= 0)
  240.   {
  241.     http_close_socket(__ka_socket);
  242.     __ka_socket = http_open_socket(__ka_port);
  243.     if(__ka_socket == 0)return NULL;
  244.     send(socket:__ka_socket, data:data);
  245.   }
  246.  
  247.   return(my_http_keepalive_recv());
  248. }
  249.  
  250. #-------------------------------------------------------------------#
  251.  
  252.  
  253. function add_cgi_dir(dir)
  254. {
  255.  local_var d, dirs, req, res;
  256.  
  257.  if ( num_cgi_dirs > max_cgi_dirs ) return 0;
  258.  
  259.  req = http_get(item:string(dir, "/non-existant-", rand()), port:port);
  260.  req = my_http_keepalive_send_recv(port:port, data:req);
  261.  if(ereg(pattern:"^HTTP/[0-9]\.[0-9] 404 ", string:req))
  262.  {
  263.   dirs = cgi_dirs();
  264.   foreach d (dirs)
  265.   {
  266.   if(d == dir)return(0);
  267.   }
  268.  
  269.   if(isnull(CGI_Dirs_List[dir]))
  270.   {
  271.    #display(CGI_Dirs_List[dir], "\n");
  272.    set_kb_item(name:"/tmp/cgibin", value:dir);
  273.    CGI_Dirs_List[dir] = 1;
  274.    num_cgi_dirs ++;
  275.   }
  276.  }
  277. }
  278.  
  279.  
  280. #--------------------------------------------------------------------------#
  281.  
  282. function add_30x(url)
  283. {
  284.  if(isnull(URLs_30x_hash[url]))
  285.  {
  286.   set_kb_item(name:string("www/", port, "/content/30x"), value:url);
  287.   URLs_30x_hash[url] = 1;
  288.  }
  289. }
  290.  
  291.  
  292. function add_auth(url)
  293. {
  294.  if(isnull(URLs_auth_hash[url]))
  295.  {
  296.   set_kb_item(name:string("www/", port, "/content/auth_required"), value:url);
  297.   URLs_auth_hash[url] = 1;
  298.   if(url == "/")RootPasswordProtected = 1;
  299.  }
  300. }
  301.  
  302. #--------------------------------------------------------------------------#
  303.  
  304. num_url = 0;
  305.  
  306. function add_url(url)
  307. {
  308.  local_var ext, dir;
  309.   
  310.  if ( num_url > 100 ) return 0;
  311.  
  312.  if(debug > 5)display("**** ADD URL ", url, "\n");
  313.  if(isnull(URLs_hash[url]))
  314.  {
  315.   URLs = make_list(URLs, url);
  316.   URLs_hash[url] = 0;
  317.    
  318.   url = ereg_replace(string:url,
  319.               pattern:"(.*)\?.*",
  320.             replace:"\1");
  321.             
  322.             
  323.   ext = ereg_replace(pattern:".*\.([^\.]*)$", string:url, replace:"\1");
  324.   if(strlen(ext) && ext[0] != "/")
  325.   {
  326.    set_kb_item(name:string("www/", port, "/content/extensions/", ext), value:url);
  327.   }
  328.   
  329.   dir = dir(url:url);
  330.   if(dir && !Dirs[dir])
  331.   {
  332.    Dirs[dir] = 1;
  333.    set_kb_item(name:string("www/", port, "/content/directories"), value:dir);
  334.    if(isnull(URLs_hash[dir]))
  335.    {
  336.     URLs = make_list(URLs, dir);
  337.     if(Apache)URLs  = make_list(URLs,  string(dir, "/?D=A"));
  338.     else if(iPlanet)URLs = make_list(URLs,  string(dir, "/?PageServices"));
  339.     URLs_hash[dir] =  0;
  340.    }
  341.   }
  342.  }
  343. }
  344.  
  345. function cgi2hash(cgi)
  346. {
  347.  local_var cur_cgi, cur_arg, i, ret;
  348.  
  349.  ret = make_list();
  350.  
  351.  for(i=0;i<strlen(cgi);i++)
  352.  {
  353.   if(cgi[i] == " " && cgi[i+1] == "[")
  354.   {
  355.     cur_arg = "";
  356.     for(i=i+2;i<strlen(cgi);i++)
  357.     {
  358.       if(cgi[i] == "]")
  359.       {
  360.         ret[cur_cgi] = cur_arg;
  361.     cur_cgi = "";
  362.     cur_arg = "";
  363.     if(i + 2 >= strlen(cgi))return ret;
  364.     i += 2;
  365.     break;
  366.       }
  367.       else cur_arg += cgi[i];
  368.     }
  369.   }
  370.   cur_cgi += cgi[i];
  371.  } 
  372.  return ret;
  373. }
  374.  
  375. function hash2cgi(hash)
  376. {
  377.  local_var ret, h;
  378.  
  379.  ret = "";
  380.  foreach h (keys(hash))
  381.  {
  382.   ret += string(h, " [", hash[h], "] ");
  383.  }
  384.  return ret;
  385. }
  386.  
  387.  
  388. function add_cgi(cgi, args)
  389. {
  390.  local_var mydir, tmp, a, new_args, common, c;
  391.  
  392.  args = string(args);
  393.  
  394.  if(isnull(CGIs[cgi]))
  395.  {
  396.   CGIs[cgi] = args;
  397.   mydir = dir(url:cgi);
  398.   if(!CGIsDirs[mydir])
  399.   {
  400.    CGIsDirs[mydir] = 1;
  401.    add_cgi_dir(dir:mydir);
  402.   }
  403.  }
  404.  else {
  405.     tmp = cgi2hash(cgi:CGIs[cgi]);
  406.     new_args = cgi2hash(cgi:args);
  407.     common = make_list();
  408.     foreach c (keys(tmp))
  409.     {
  410.      common[c] = tmp[c];
  411.     }
  412.     
  413.     foreach c (keys(new_args))
  414.     {
  415.      if(isnull(common[c]))common[c] = new_args[c];
  416.     }
  417.     CGIs[cgi] = hash2cgi(hash:common);
  418.     }
  419. }
  420.  
  421.  
  422.  
  423. #---------------------------------------------------------------------------#
  424.  
  425. function dir(url)
  426. {
  427.  return ereg_replace(pattern:"(.*)/[^/]*", string:url, replace:"\1");
  428. }
  429.  
  430. function remove_cgi_arguments(url)
  431. {
  432.  local_var idx, cgi, cgi_args, args, arg, a, b;
  433.  
  434.  # Remove the trailing blanks
  435.  while(url[strlen(url) - 1] == " ")
  436.  {
  437.   url = substr(url, 0, strlen(url) - 2);
  438.  }
  439.  
  440.  idx = stridx(url, "?");
  441.  if(idx < 0)
  442.   return url;
  443.  else if(idx >= strlen(url) - 1)
  444.  {
  445.   cgi = substr(url, 0, strlen(url) - 2);
  446.   add_cgi(cgi:cgi, args:"");
  447.   return cgi;
  448.  }
  449.  else
  450.  {
  451.   if(idx > 1)cgi = substr(url, 0, idx - 1);
  452.   else cgi = ".";
  453.   cgi_args = split(substr(url, idx + 1, strlen(url) - 1), sep:"&");
  454.   foreach arg (make_list(cgi_args)) 
  455.   {
  456.    arg = arg - "&";
  457.    arg = arg - "amp;";
  458.    a = ereg_replace(string:arg, pattern:"(.*)=.*", replace:"\1");
  459.    b = ereg_replace(string:arg, pattern:".*=(.*)", replace:"\1");
  460.    if(a != b)
  461.        args = string(args, a , " [", b, "] ");
  462.    else
  463.         args = string(args, arg, " [] ");
  464.   }
  465.   add_cgi(cgi:cgi, args:args);
  466.   return cgi;
  467.  }
  468. }
  469.  
  470.  
  471. function basename(name, level)
  472. {
  473.  local_var i;
  474.  
  475.  if(strlen(name) == 0)
  476.   return NULL;
  477.   
  478.  
  479.   for(i = strlen(name) - 1; i >= 0 ; i --)
  480.   {
  481.    if(name[i] == "/")
  482.    {
  483.     level --;
  484.     if(level < 0)
  485.     { 
  486.      return(substr(name, 0, i));
  487.     }
  488.    }
  489.  }
  490.  
  491.  # Level is too high, we return /
  492.  return "/";
  493. }
  494.  
  495.  
  496.  
  497. function canonical_url(url, current)
  498. {
  499.  local_var num_dots, i, location ;
  500.  
  501.  
  502.  
  503.  if(debug > 1)display("***** canonical '", url, "' (current:", current, ")\n");
  504.  
  505.  if(strlen(url) == 0)
  506.   return NULL;
  507.   
  508.  if(url[0] == "#")
  509.   return NULL;
  510.  
  511.  
  512.  if(url == "./" || url == ".")
  513.    return current;
  514.   
  515.  
  516.  if(debug > 2)display("**** canonical(again) ", url, "\n");
  517.  
  518.  if(ereg(pattern:"[a-z]*:", string:url, icase:TRUE))
  519.  {
  520.   if(ereg(pattern:"^http://", string:url, icase:TRUE))
  521.   {
  522.    location = ereg_replace(string:url, pattern:"http://([^/]*)/.*", replace:"\1", icase:TRUE);
  523.    if(location != url)
  524.    {
  525.     if(location != get_host_name())return NULL;
  526.     else return remove_cgi_arguments(url:ereg_replace(string:url, pattern:"http://[^/]*/([^?]*)", replace:"/\1", icase:TRUE));
  527.    }
  528.   }
  529.  }
  530.  else
  531.  {
  532.  if(url == "//")  return "/";
  533.  
  534.  if(ereg(pattern:"^//.*", string:url, icase:TRUE))
  535.  {
  536.   location = ereg_replace(string:url, pattern:"//([^/]*)/.*", replace:"\1", icase:TRUE);
  537.   if(location != url)
  538.   {
  539.    if(location == get_host_name())return remove_cgi_arguments(url:ereg_replace(string:url, pattern:"//[^/]*/([^?]*)", replace:"/\1", icase:TRUE));
  540.   }
  541.   return NULL;
  542.  }
  543.  
  544.  if(url[0] == "/")
  545.   return remove_cgi_arguments(url:url);
  546.  else
  547.  {
  548.   i = 0;
  549.   num_dots = 0;
  550.  
  551.   while(i < strlen(url) - 2 && url[i] == "." && url[i+1] == "." && url[i+2] == "/")
  552.   {
  553.    num_dots ++;
  554.    url = url - "../";
  555.    if(strlen(url) == 0)break;
  556.   }
  557.   
  558.   while(i < strlen(url) && url[i] == "." && url[i+1] == "/")
  559.   {
  560.     url = url - "./";
  561.     if(strlen(url) == 0)break;
  562.   }
  563.   url = string(basename(name:current, level:num_dots), url);
  564.  }
  565.  
  566.  i = stridx(url, "#");
  567.  if(i >= 0)url = substr(url, 0, i - 1);
  568.  
  569.  
  570.  if(url[0] != "/")
  571.      return remove_cgi_arguments(string("/", url));
  572.  else
  573.      return remove_cgi_arguments(url:url);
  574.  }
  575.  return NULL;
  576. }
  577.  
  578.  
  579.  
  580. #--------------------------------------------------------------------#
  581.  
  582.  
  583. function my_http_get(item, port)
  584. {
  585.  local_var ret, accept, idx;
  586.  
  587.  ret = http_get(item:page, port:port);
  588.  accept = egrep(string:ret, pattern:"^Accept:.*");
  589.  ret = ret - accept;
  590.  idx = stridx(ret, string("\r\n\r\n"));
  591.  
  592.  
  593.  ret = insstr(ret, string("\r\nAccept: text/html, text/xml\r\n\r\n"), idx);
  594.  return ret;
  595. }
  596.  
  597.  
  598. function extract_location(data)
  599. {
  600.  local_var loc, url;
  601.  
  602.  
  603.  
  604.  loc = egrep(string:data, pattern:"^Location: ");
  605.  if(!loc) return NULL;
  606.  
  607.  loc = loc - string("\r\n");
  608.  loc = ereg_replace(string:loc, 
  609.                               pattern:"Location: (.*)$",
  610.                               replace:"\1");
  611.  
  612.  
  613.  
  614.   url = canonical_url(url:loc, current:"/"); 
  615.   if( url )
  616.   {
  617.    add_url(url : url);
  618.    return url;
  619.   }
  620.   
  621.   return NULL;
  622. }
  623.  
  624.  
  625.  
  626. function retr( port, page )
  627. {
  628.  local_var req, resp, q;
  629.  
  630.  if( debug )display("*** RETR ", page, "\n");
  631.   
  632.  req = my_http_get(item:page, port:port);
  633.  resp = my_http_keepalive_send_recv(port:port, data:req);
  634.  if( resp == NULL ) exit(0); # No web server
  635.  
  636.  if(!match(pattern:"HTTP* 200 *", string:resp))
  637.  {
  638.   if(match(pattern:"HTTP* 401 *", string:resp) ||
  639.      match(pattern:"HTTP* 403 *", string:resp))
  640.      {
  641.       add_auth(url:page);
  642.       return NULL;
  643.      }
  644.   if(match(pattern:"HTTP* 301 *", string:resp) ||
  645.      match(pattern:"HTTP* 302 *", string:resp))
  646.   { 
  647.    q = egrep(pattern:"^Location:.*", string:resp);
  648.    add_30x(url:page);
  649.    
  650.    # Don't echo back what we added ourselves...
  651.    if(!(("?PageServices" >< page || "?D=A" >< page) && ("?PageServices" >< q || "?D=A" >< q)))
  652.        extract_location(data:resp);
  653.    return NULL;
  654.   }
  655.  }
  656.  
  657.  if(egrep(pattern:"^Server:.*Apache.*", string:resp))Apache ++;
  658.  else if(egrep(pattern:"^Server:.*Netscape.*", string:resp))iPlanet ++;
  659.  
  660.  if(!egrep(pattern:"^Content-Type: text/(xml|html).*", string:resp))
  661.      return NULL;
  662.  else 
  663.      {
  664.     resp = strstr(resp, string("\r\n\r\n"));
  665.     if(!resp)return NULL; # Broken web server ?
  666.     resp = str_replace(string:resp, find:string("\r\n"), replace:" ");
  667.     resp = str_replace(string:resp, find:string("\n"), replace:" ");
  668.     resp = str_replace(string:resp, find:string("\t"), replace:" ");
  669.      return resp;
  670.     }
  671. }
  672.  
  673. #---------------------------------------------------------------------------#
  674.  
  675.  
  676. function token_split(content)
  677. {
  678.  local_var i, j, k, str;
  679.  local_var ret, len, num;
  680.  
  681.  num = 0;
  682.  
  683.  ret = make_list();
  684.  len = strlen(content);
  685.  
  686.  for (i=0;i<len;i++)
  687.  {
  688.   if(((i + 3) < len) && content[i]=="<" && content[i+1]=="!" && content[i+2]=="-" && content[i+3]=="-")
  689.   {
  690.    j = stridx(content, "-->", i);
  691.    if( j < 0)return(ret);
  692.    i = j;
  693.   }
  694.  else  
  695.   if(content[i]=="<")
  696.   {
  697.    str = "";
  698.    i ++;
  699.    
  700.    while(content[i] == " ")i ++;
  701.    
  702.    for(j = i; j < len ; j++)
  703.    {
  704.     if(content[j] == '"')
  705.     {
  706.       k = stridx(content, '"', j + 1);
  707.       if(k < 0){
  708.           return(ret); # bad page
  709.     }
  710.       str = str + substr(content, j, k);
  711.       j = k;
  712.     }
  713.     else if(content[j] == '>')
  714.     {        
  715.      if(ereg(pattern:"^(a|area|frame|meta|iframe|link|img|form|/form|input|button|textarea|select|applet)( .*|$)", string:str, icase:TRUE))
  716.          {
  717.         num ++;
  718.          ret = make_list(ret, str);
  719.         if ( num > 50 ) return ret; # Too many items
  720.     }
  721.      break;
  722.     }
  723.     else str = str + content[j];
  724.    }
  725.    i = j;
  726.   }
  727.  }
  728.  
  729.  return(ret);
  730. }
  731.  
  732.  
  733.  
  734. function token_parse(token)
  735. {
  736.  local_var ret, i, j, len, current_word, word_index, current_value, char;
  737.  
  738.  
  739.  ret = make_list();
  740.  len = strlen(token);
  741.  current_word = "";
  742.  word_index = 0;
  743.  
  744.  for( i = 0 ; i < len ; i ++)
  745.  {
  746.   if((token[i] == " ")||(token[i] == "="))
  747.   {
  748.    while(i+1 < len && token[i+1] == " ")i ++;
  749.    if(i >= len)break;
  750.    
  751.    if(word_index == 0)
  752.    {
  753.     ret["nasl_token_type"] = tolower(current_word);
  754.    }
  755.    else
  756.    {
  757.     while(i+1 < len && token[i] == " ")i ++;
  758.     if(token[i] != "=")
  759.     {
  760.          ret[tolower(current_word)] = NULL; 
  761.     }
  762.     else
  763.     {
  764.         i++;
  765.     char = NULL;
  766.     if(i >= len)break;
  767.         if(token[i] == '"')char = '"';
  768.     else if(token[i] == "'")char = "'";
  769.     
  770.     if(!isnull(char))
  771.      {
  772.      j = stridx(token, char, i + 1);
  773.      if(j < 0)
  774.       {
  775.       if(debug)display("PARSE ERROR 1\n");
  776.       return(ret); # Parse error
  777.       }
  778.      ret[tolower(current_word)] = substr(token, i + 1, j - 1);
  779.      while(j+1 < len &&  token[j+1]==" ")j++;
  780.      i = j;
  781.     }
  782.         else
  783.         {
  784.          j = stridx(token, ' ', i + 1);
  785.      if(j < 0)
  786.       {
  787.        j = strlen(token);
  788.       }
  789.      ret[tolower(current_word)] = substr(token, i, j - 1);
  790.      i = j;
  791.        }
  792.      }
  793.    }
  794.     current_word = "";
  795.     word_index ++;
  796.   }
  797.   else {
  798.       if(i < len)current_word = current_word + token[i];
  799.     }
  800.  }
  801.  
  802.  if(!word_index)ret["nasl_token_type"] = tolower(current_word);
  803.  return ret;
  804. }
  805.  
  806.  
  807. #-------------------------------------------------------------------------#
  808.  
  809. function parse_java(elements) 
  810. {
  811.     archive = elements["archive"];
  812.     code = elements["code"];
  813.     codebase = elements["codebase"];
  814.  
  815.     if (codebase) 
  816.     {
  817.          if (archive)
  818.             set_kb_item(name:string("www/", port, "/java_classfile"), value:string(codebase,"/",archive));
  819.          if (code)
  820.              set_kb_item(name:string("www/", port, "/java_classfile"), value:string(codebase,"/",code));
  821.     } 
  822.     else 
  823.     {
  824.          if (archive)
  825.             set_kb_item(name:string("www/", port, "/java_classfile"), value:archive);
  826.          if (code)
  827.             set_kb_item(name:string("www/", port, "/java_classfile"), value:code);
  828.     }
  829. }
  830.  
  831.  
  832.  
  833.  
  834.  
  835.  
  836.  
  837. function parse_javascript(elements, current)
  838. {
  839.   local_var url, pat;
  840.   
  841.   if(debug > 15)display("*** JAVASCRIPT\n");
  842.   
  843.   pat = string(".*window\\.open\\('([^',", raw_string(0x29), "]*)'.*\\)*");
  844.   url = ereg_replace(pattern:pat,
  845.                string:elements["onclick"],
  846.              replace:"\1",
  847.              icase:TRUE);
  848.         
  849.            
  850.   if( url == elements["onclick"])
  851.    return NULL;
  852.   
  853.   url = canonical_url(url:url, current:current); 
  854.   if( url )
  855.   {
  856.    add_url(url : url);
  857.    return url;
  858.   }
  859.   
  860.   return NULL;
  861. }
  862.  
  863.  
  864. function parse_dir_from_src(elements, current)
  865. {
  866.  local_var src, dir;
  867.  
  868.  src = elements["src"];
  869.  if( ! src ) return NULL;
  870.  
  871.  src = canonical_url(url:src, current:current);
  872.  dir = dir(url:src);
  873.  if(dir && !Dirs[dir])
  874.  {
  875.   Dirs[dir] = 1;
  876.   set_kb_item(name:string("www/", port, "/content/directories"), value:dir);
  877.   if(isnull(URLs_hash[dir]))
  878.    {
  879.     URLs = make_list(URLs, dir);
  880.     URLs_hash[dir] =  0;
  881.    }
  882.   }
  883. }
  884.  
  885.  
  886. function parse_href_or_src(elements, current)
  887. {
  888.  local_var href;
  889.  
  890.  href = elements["href"];
  891.  if(!href)href = elements["src"];
  892.  
  893.  if(!href){
  894.     return NULL;
  895.     }
  896.  
  897.  href = canonical_url(url:href, current:current);
  898.  if( href )
  899.  {
  900.   add_url(url: href);
  901.   return href;
  902.  }
  903. }
  904.  
  905.  
  906. function parse_refresh(elements, current)
  907. {
  908.  local_var href, content, t, sub;
  909.  
  910.  content = elements["content"];
  911.  
  912.  if(!content)
  913.   return NULL;
  914.  t = strstr(content, ";");
  915.  if( t != NULL ) content = substr(t, 1, strlen(t) - 1);
  916.  
  917.  content = string("a ", content);
  918.  sub = token_parse(token:content);
  919.  
  920.  if(isnull(sub)) return NULL;
  921.  
  922.  href = sub["url"];
  923.  if(!href)
  924.   return NULL;
  925.  
  926.  href = canonical_url(url:href, current:current);
  927.  if ( href )
  928.  {
  929.   add_url(url: href);
  930.   return href;
  931.  }
  932. }
  933.  
  934.  
  935. function parse_form(elements, current)
  936. {
  937.  local_var action;
  938.  
  939.  action = elements["action"];
  940.  
  941.  action = canonical_url(url:action, current:current);
  942.  if ( action )
  943.    return action;
  944.  else 
  945.    return NULL;
  946. }
  947.  
  948.  
  949. function pre_parse(data, src_page)
  950. {
  951.     local_var php_path, fp_save, data2;
  952.  
  953.     if ("Index of /" >< data)
  954.     {
  955.             if(!Misc[src_page])
  956.         {
  957.         if("?D=A" >!< src_page && "?PageServices" >!< src_page)
  958.             {
  959.                   misc_report = misc_report + string("Directory index found at ", src_page, "\n");
  960.             Misc[src_page] = 1;
  961.          }
  962.         }
  963.     }
  964.     
  965.     if ("<title>phpinfo()</title>" >< data)
  966.     {
  967.             if(!Misc[src_page])
  968.         {
  969.             misc_report = misc_report + string("Extraneous phpinfo() script found at ", src_page, "\n"); 
  970.         Misc[src_page] = 1;
  971.         }
  972.             
  973.     }
  974.     
  975.     if("Fatal" >< data || "Warning" >< data)
  976.     {
  977.     data2 = strstr(data, "Fatal");
  978.     if(!data2)data2 = strstr(data, "Warning");
  979.     
  980.     data2 = strstr(data2, "in <b>");
  981.     
  982.     php_path = ereg_replace(pattern:"in <b>([^<]*)</b>.*", string:data2, replace:"\1");
  983.     if (php_path != data2)
  984.     {
  985.         if (!Misc[src_page])
  986.         {
  987.             misc_report = misc_report + string("PHP script discloses physical path at ", src_page, " (", php_path, ")\n");
  988.         Misc[src_page] = 1;
  989.         }
  990.      }
  991.     }
  992.     
  993.    
  994.     data2 = strstr(data, "unescape");
  995.     
  996.     if(data2 && ereg(pattern:"unescape..(%([0-9]|[A-Z])*){200,}.*", string:data2))
  997.     {
  998.      if(!Misc[src_page])
  999.      {
  1000.       misc_report += string(src_page, " seems to have been 'encrypted' with HTML Guardian\n");
  1001.       guardian ++;
  1002.      }
  1003.     }
  1004.     
  1005.     if("CREATED WITH THE APPLET PASSWORD WIZARD WWW.COFFEECUP.COM" >< data)
  1006.     {
  1007.      if(!Misc[src_page])
  1008.      {
  1009.       misc_report += string(src_page, " seems to contain links 'protected' by CoffeCup\n");
  1010.       coffeecup++;
  1011.      }
  1012.      
  1013.       
  1014.     }
  1015.  
  1016.     if("SaveResults" >< data)
  1017.     { 
  1018.     fp_save = ereg_replace(pattern:string("(.*SaveResults.*U-File=)", quote, "(.*)", quote, ".*"), string:data, replace:"\2");
  1019.     if (fp_save != data)
  1020.      {
  1021.         if (!Misc[src_page])
  1022.         {
  1023.             misc_report = misc_report + string("FrontPage form stores results in web root at ", src_page, " (", fp_save, ")\n");
  1024.         Misc[src_page] = 1;
  1025.         }   
  1026.      }
  1027.    }
  1028. }
  1029.  
  1030.  
  1031.  
  1032. function parse_main(current, data)
  1033. {
  1034.  local_var tokens, elements, cgi, form_cgis, form_cgis_level, args, store_cgi;
  1035.  
  1036.  form_cgis = make_list();
  1037.  form_cgis_level = 0;
  1038.  argz = NULL;
  1039.  store_cgi = 0;
  1040.  tokens = token_split(content: data);
  1041.  foreach token (tokens)
  1042.  {
  1043.    elements = token_parse(token:token);
  1044.    if(!isnull(elements))
  1045.    {
  1046.     
  1047.     if(elements["onclick"])
  1048.         parse_javascript(elements:elements, current:current);
  1049.  
  1050.     if ( elements["nasl_token_type"] == "applet")
  1051.         parse_java(elements:elements);
  1052.     
  1053.     if(elements["nasl_token_type"] == "a"       || 
  1054.        elements["nasl_token_type"] == "link"       ||
  1055.        elements["nasl_token_type"] == "frame"      ||
  1056.        elements["nasl_token_type"] == "iframe"      ||
  1057.        elements["nasl_token_type"] == "area")
  1058.         if( parse_href_or_src(elements:elements, current:current) == NULL) {
  1059.       if(debug > 20)display("ERROR - ", token, "\n");
  1060.       }
  1061.     if(elements["nasl_token_type"] == "img")
  1062.         parse_dir_from_src(elements:elements, current:current);
  1063.     
  1064.     if(elements["nasl_token_type"] == "meta")
  1065.         parse_refresh(elements:elements, current:current);
  1066.               
  1067.     if( elements["nasl_token_type"] == "form" )
  1068.     {
  1069.       cgi = parse_form(elements:elements, current:current);
  1070.       if( cgi )
  1071.       {
  1072.        form_cgis[form_cgis_level] = cgi;
  1073.        store_cgi = 1;
  1074.       }
  1075.       form_cgis_level ++;
  1076.     }
  1077.     
  1078.    if( elements["nasl_token_type"] == "/form")
  1079.     {
  1080.      form_cgis_level --;
  1081.      if( store_cgi != 0) add_cgi(cgi:form_cgis[form_cgis_level], args:argz);
  1082.      argz = "";
  1083.      store_cgi = 0;
  1084.     } 
  1085.    
  1086.    if( elements["nasl_token_type"] == "input" ||
  1087.        elements["nasl_token_type"] == "select")
  1088.     {
  1089.      if(elements["name"])
  1090.          argz += string( elements["name"], " [", elements["value"], "] ");
  1091.     }
  1092.    }
  1093.  }
  1094. }
  1095.  
  1096.  
  1097. #----------------------------------------------------------------------#
  1098. #                MAIN()                       #
  1099. #----------------------------------------------------------------------#
  1100.  
  1101.  
  1102.  
  1103. start_page = script_get_preference("Start page : ");
  1104. if(isnull(start_page) || start_page == "")start_page = "/";
  1105.  
  1106.  
  1107. max_pages = int(script_get_preference( "Number of pages to mirror : " ));
  1108. if(max_pages <= 0)
  1109.   if (COMMAND_LINE)
  1110.    max_pages = 9999;
  1111.   else
  1112.    max_pages = 30;
  1113.  
  1114. dirs = get_kb_list(string("www/", port, "/content/directories"));
  1115.  
  1116.  
  1117. num_cgi_dirs = 0;
  1118. if ( thorough_tests ) max_cgi_dirs = 1024;
  1119. else max_cgi_dirs = 16;
  1120.  
  1121.  
  1122.  
  1123. debug = 0;
  1124.  
  1125. port = get_http_port(default:80);
  1126.  
  1127. if(!get_port_state(port))exit(0);
  1128.  
  1129. URLs = make_list(start_page);
  1130. if(dirs) URLs = make_list(start_page, dirs);
  1131. URLs_hash[start_page] = 0;
  1132.  
  1133.  
  1134. Apache = 0;
  1135. iPlanet = 0;
  1136.  
  1137. CGIs = make_list();
  1138. Misc = make_list();
  1139. Dirs = make_list();
  1140.  
  1141. CGI_Dirs_List = make_list();
  1142.  
  1143. URLs_30x_hash = make_list();
  1144. URLs_auth_hash = make_list();
  1145.  
  1146.  
  1147. Code404 = make_list();
  1148.  
  1149. misc_report = "";
  1150. cnt = 0;
  1151.  
  1152. RootPasswordProtected = 0;
  1153.  
  1154. guardian  = 0;
  1155. coffeecup = 0;
  1156.  
  1157. foreach URL (URLs)
  1158.  if(!URLs_hash[URL])
  1159.  {
  1160.      page = retr(port:port, page:URL);
  1161.     cnt ++;
  1162.     pre_parse(src_page:URL, data:page);
  1163.     parse_main(data:page, current:URL);
  1164.      URLs_hash[URL] = 1;
  1165.     if(cnt >= max_pages)break;
  1166.  }
  1167. }
  1168.  
  1169.  
  1170. if(cnt == 1)
  1171. {
  1172.  if(RootPasswordProtected)
  1173.  {
  1174.   set_kb_item(name:string("www/", port, "/password_protected"), value:TRUE);
  1175.  }
  1176. }
  1177. #foreach URL (URLs)
  1178. #{
  1179. # display(URL,"\n");
  1180. #}
  1181.  
  1182. #display("-----------------------------------------\n");
  1183.  
  1184.  
  1185. report = "";
  1186.  
  1187. foreach foo (keys(CGIs))
  1188. {
  1189.  args = CGIs[foo];
  1190.  if(!args) args = "";
  1191.  set_kb_item(name:string("www/", port, "/cgis"), value:string(foo, " - ", args));
  1192.  
  1193.   
  1194.  if(!report) 
  1195.      report = string("The following CGI have been discovered :\n\nSyntax : cginame (arguments [default value])\n\n", foo, " (", args, ")\n");
  1196.  else
  1197.      report = string(report, foo, " (", args, ")\n");
  1198. }
  1199.  
  1200. if(misc_report)
  1201.  
  1202.  report =  string(report, "\n\n", misc_report);
  1203. }
  1204.  
  1205.  
  1206. if(guardian)
  1207. {
  1208.  report += string("
  1209.  
  1210. HTML Guardian is a tool which claims to encrypt web pages, whereas it simply
  1211. does a transposition of the content of the page. It is is no way a safe
  1212. way to make sure your HTML pages are protected.
  1213.  
  1214. See also : http://www.securityfocus.com/archive/1/315950
  1215. BID : 7169");
  1216. }
  1217.  
  1218.  
  1219. if(coffeecup)
  1220. {
  1221.  report += "
  1222.  
  1223. CoffeeCup Wizard is a tool which claims to encrypt links to web pages,
  1224. to force users to authenticate before they access the links. However,
  1225. the 'encryption' used is a simple transposition method which can be 
  1226. decoded without the need of knowing a real username and password.
  1227.  
  1228. BID : 6995 7023";
  1229. }
  1230.  
  1231. if(strlen(report))
  1232. {
  1233.  security_note(port:port, data:report);
  1234. }
  1235.  
  1236.